package br.unifor.mia.olio.web.servlet;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import br.unifor.mia.olio.InstanceType;
import br.unifor.mia.olio.SessionRemote;

/**
 * Servlet implementation class ExecutionServlet
 */
@WebServlet("/ExecutionServlet")
public class ExecutionServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	

	protected Logger logger = Logger.getLogger(getClass().getName());

	protected static SessionRemote remote = null;

	public SessionRemote getFacade() {

		if (remote == null) {

			try {
				InitialContext ic = new InitialContext();

				remote = (SessionRemote) ic.lookup("java:app/OlioTestAnaliserEJB/Session");
			} catch (NamingException e) {
				e.printStackTrace();
			}
		}

		return remote;
	}

	/**
	 * @see HttpServlet#HttpServlet()
	 */
	public ExecutionServlet() {
		super();
		// TODO Auto-generated constructor stub
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		doSomething(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		doSomething(request, response);
	}

	protected void doSomething(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		Map<KeyExec, Double>  map = consolidate(request);

		request.setAttribute("map", map);
		
		request.getRequestDispatcher("/execution/chart.jsp").forward(request, response);
	}

	public Map<KeyExec, Double> consolidate(HttpServletRequest request) {
		List<br.unifor.mia.olio.Execution> executions = loadExecutions(request);

		Map<KeyExec, Double> result = null;
		
		List<InstanceType> instances = new ArrayList<InstanceType>();
		Set<Integer> users = new HashSet<Integer>();
		
		request.setAttribute("instances", instances);
		
		final InstanceType DUMMY = new InstanceType();
		DUMMY.setId(-1l);

		if (executions != null) {

			result = new HashMap<KeyExec, Double>();

			
			

			InstanceType instanceType = DUMMY;
			int total = 0;
			int totalPassed = 0;

			Integer user = 0;

			for (br.unifor.mia.olio.Execution execution : executions) {

				if (!instanceType.equals(execution.getInstanceType())) {

					instances.add(execution.getInstanceType());

					if (!DUMMY.equals(instanceType)) {
						
						result.put(new KeyExec(user, instanceType),
								 (double) totalPassed / (double) total);
						total = 0;
						totalPassed = 0;

						user = 0;
					}
					instanceType = execution.getInstanceType();

				}

				if (!user.equals(execution.getUsers())) {

					users.add(execution.getUsers());

					if (user != 0) {
						// computa
						result.put(new KeyExec(user, instanceType),
								(double) totalPassed / (double) total);
						total = 0;
						totalPassed = 0;
						
						user = 0;
					}

					user = execution.getUsers();
				}
				
				total++;
				if (execution.getSuccess()) {
					totalPassed++;
				}

			}
			result.put(new KeyExec(user, instanceType),
					(double) totalPassed / (double) total);
		}
		
		List<Integer> orderedUsers = new ArrayList<Integer>(users.size());
		for (Integer user : users) {
			orderedUsers.add(user);
		}
		
		Collections.sort(orderedUsers,new Comparator<Integer>(){

			@Override
			public int compare(Integer arg0, Integer arg1) {
				
				return arg0.compareTo(arg1);
			}
			
		} );

		request.setAttribute("users", orderedUsers);
		logger.info("users " + orderedUsers.size());
		logger.info("instances " + instances.size());

		return result;
	}

	public List<br.unifor.mia.olio.Execution> loadExecutions(
			HttpServletRequest request) {

		List<br.unifor.mia.olio.Execution> retorno = null;
		if (null != request.getParameterValues("id")) {
			String[] strIds = request.getParameterValues("id");

			List<Long> ids = new ArrayList<Long>(strIds.length);

			for (String strId : strIds) {
				ids.add(new Long(strId));
			}
			
			request.setAttribute("ids", ids);

			retorno = getFacade().getExecutions(ids);

			logger.info(retorno.size() + " ");

		} else {
			logger.info(null);
		}

		return retorno;
	}

	public static class KeyExec {

		public final InstanceType instanceType;
		public final Integer user;
		
		

		public KeyExec(Integer user, InstanceType instanceType) {
			this.user = user;
			this.instanceType = instanceType;
		}
		
		public static KeyExec getKey(Integer user, InstanceType instanceType){
			return new KeyExec(user, instanceType);
		}

		@Override
		public int hashCode() {
			return user.hashCode() + (instanceType.hashCode() * 7);
		}

		@Override
		public boolean equals(Object obj) {

			if (obj == this) {
				return true;
			}else if(obj instanceof KeyExec){
				
				KeyExec other = (KeyExec) obj;
				return other.user.equals(this.user)
						&& other.instanceType.equals(this.instanceType);
			}

			return false;
		}
	}

}
